package org.wevil.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 反射工具类
 *
 * @author wanglei
 * @since 2020/12/17
 */
public class ReflectUtil {
        
    /**
     * 调用方法
     * 
     * @param clazz 要调用的类
     * @param classPackageName 调用类的包全名。举例：com.example.springboottest.main.Main1
     * @param methodName 方法名
     * @param parameterTypes 方法参数类型
     * @param obj 调用的对象
     * @param args 方法参数
     * @return 返回调用结果
     * @throws SecurityException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public static Object invokeMethod(
            Class<?> clazz, 
            String classPackageName, 
            String methodName, 
            Class<?>[] parameterTypes,
            Object obj, 
            Object[] args

    ) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
        ClassLoader classLoader = clazz.getClassLoader();
        Class<?> loadClass = classLoader.loadClass(classPackageName);
        Method method = loadClass.getMethod(methodName, parameterTypes);
        return method.invoke(obj, args);
    }

    /**
     * map转类对应的对象
     *
     * @param clazz     类
     * @param keyValues 字段名称和值
     * @author wanglei
     * @since 2020/12/17
     */
    public static <E> E map2Object(Class<E> clazz, Map<String, ?> keyValues) {
        E instance = null;
        try{
            // 根据class生成一个实例
            instance = clazz.newInstance();
            // 获取class的所有字段
            Field[] fields = clazz.getDeclaredFields();
            // 遍历要赋值的map
            for (Map.Entry<String, ?> entry : keyValues.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                for(Field field : fields){
                    // 字段名称
                    String fieldName = field.getName();
                    // 字段类型
                    Class<?> type = field.getType();
                    // 获取一个字段首字母大写
                    String upperField = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                    // 获取该字段的set方法
                    Method setMethod = clazz.getMethod("set" + upperField, type);
                    // 跳过序列号
                    if (fieldName.equals("serialVersionUID")) {
                        continue;
                    }
                    // 如果名称能够对上
                    if(fieldName.equals(key)){
                        // 根据数据类型赋值
                        setMethod.invoke(instance, value);
                    }
                }
            }
        }catch (InstantiationException | IllegalAccessException ie){
            System.out.println("创建对象实例失败！");
        }catch(NoSuchMethodException | SecurityException  ne){
            System.out.println("获取set方法失败！");
        }catch(IllegalArgumentException | InvocationTargetException le){
            System.out.println("赋值失败！");
        }
        return instance;
    }

    /**
     * 给对象赋值
     *
     * @param instance     对象
     * @param keyValues 字段名称和值
     */
    public static <E> E assignValue(E instance, Map<String, ?> keyValues) {
        try{
            // 获取class的所有字段
            Field[] fields = instance.getClass().getDeclaredFields();
            // 遍历要赋值的map
            for (Map.Entry<String, ?> entry : keyValues.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                for(Field field : fields){
                    // 字段名称
                    String fieldName = field.getName();
                    // 字段类型
                    Class<?> type = field.getType();
                    // 获取一个字段首字母大写
                    String upperField = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                    // 获取该字段的set方法
                    Method setMethod = instance.getClass().getMethod("set" + upperField, type);
                    // 跳过序列号
                    if (fieldName.equals("serialVersionUID")) {
                        continue;
                    }
                    // 如果名称能够对上
                    if(fieldName.equals(key)){
                        // 根据数据类型赋值
                        setMethod.invoke(instance, value);
                    }
                }
            }
        }catch (IllegalAccessException ie){
            System.out.println("创建对象实例失败！");
        }catch(NoSuchMethodException | SecurityException  ne){
            System.out.println("获取set方法失败！");
        }catch(IllegalArgumentException | InvocationTargetException le){
            System.out.println("赋值失败！");
        }
        return instance;
    }
}
